import java.util.Set;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.Random;

/**
 * Class Room - a room in an adventure game.
 *
 * This class is part of the "World of Zuul" application. 
 * "World of Zuul" is a very simple, text based adventure game.  
 *
 * A "Room" represents one location in the scenery of the game.  It is 
 * connected to other rooms via exits.  For each existing exit, the room 
 * stores a reference to the neighboring room.
 * 
 * @author  Michael Kölling and David J. Barnes
 * @version 2011.08.09
 */

public class Room 
{
    private String description;
    private HashMap<String, Room> exits;        // stores exits of this room.
    private HashMap<String, String> lockedExits;
    private HashMap<String, Item> inventory;
    
    private Monster monster;
    
    static ArrayList<Room> roomList = new ArrayList<Room>();

    /**
     * Create a room described "description". Initially, it has
     * no exits. "description" is something like "a kitchen" or
     * "an open court yard".
     * @param description The room's description.
     */
    public Room(String description) 
    {
        this.description = description;
        exits = new HashMap<String, Room>();
        lockedExits = new HashMap<String, String>();
        inventory = new HashMap<String, Item>();
        roomList.add(this);
    }
    
    /**
     * Add an item to a room's inventory
     * @param item The item to add
     */
    public void addItem(Item item)
    {
        inventory.put(item.getName(), item);
    }
    
    /**
     * Check if a room's inventory has a certain item
     * @param itemName The name of the item to check for
     */
    public boolean hasItem(String itemName)
    {
        return inventory.containsKey(itemName);
    }
    
    /**
     * Remove an item from the room's inventory
     * @param itemName The name of the item to remove
     */
    public void removeItem(String itemName)
    {
        inventory.remove(itemName);
    }
    
    /**
     * Get an item from a room
     * @param The name of the item you want.
     */
    public Item getItem(String itemName)
    {
        return inventory.get(itemName);
    }
    
    /**
     * Print an overview of all items in this room's inventory
     */
    public String getItemOverview()
    {
        String itemOverview = "Located items: ";
        boolean firstWord = false;
        for(String currentItem : inventory.keySet())
        {
            if(firstWord == false){
                itemOverview = itemOverview + " " + inventory.get(currentItem).getName();
                firstWord = true;
            }
            else{
                itemOverview = itemOverview + ", " + inventory.get(currentItem).getName();
            }
        }
        
        if(itemOverview == "Located items:"){
            itemOverview = itemOverview + " " + "none";
        }
        return itemOverview;
    }
    
    /**
     * Get the description of a certain item
     * @param itemName the name of the item
     */
    public String getItemDescription(String itemName)
    {
        return inventory.get(itemName).getDescription();
    }
    
    /**
     * Get the strength of a certain item
     * @param itemName the name of the item
     */
    public int getItemStrength(String itemName)
    {
        return inventory.get(itemName).getStrength();
    }
    
    /**
     * Get the weight of a certain item
     * @param itemName the name of the item
     */
    public int getItemWeight(String itemName)
    {
        return inventory.get(itemName).getWeight();
    }
    
    //overwritten by TeleportRoom, this function is just here to prevent compilation errors
    public Room getRandomRoom()
    {
        return this;
    }
    
    //overwritten by TeleportRoom, this function is just here to prevent compilation errors
    public boolean getFallen()
    {
        return true;
    }
    
    //overwritten by TeleportRoom, this function is just here to prevent compilation errors
    public void setFallen(boolean fallen){}
    
    //overwritten by TeleportRoom, this function is just here to prevent compilation errors
    public void setroomToFallTo(Room roomToFallTo){}
    
    //overwritten by TeleportRoom, this function is just here to prevent compilation errors
    public Room getRoomToFallTo(){
        return this;
    }
        
    
    /**
     * Define an exit from this room.
     * @param direction The direction of the exit.
     * @param neighbor  The room to which the exit leads.
     */
    public void setExit(String direction, Room neighbor) 
    {
        exits.put(direction, neighbor);
    }
    
    /**
     * Define a lock for an exit
     * @param direction The direction to be locked
     * @param itemNeededToUnlock The name of the item needed to unlock this direction
     */
    public void lockExit(String direction, String itemNeededToUnlock)
    {
        lockedExits.put(direction, itemNeededToUnlock);
    }

    /**
     * @return The short description of the room
     * (the one that was defined in the constructor).
     */
    public String getShortDescription()
    {
        return description;
    }

    /**
     * Return a description of the room in the form:
     *     You are in the kitchen.
     *     Exits: north west
     * @return A long description of this room
     */
    public String getLongDescription()
    {
        if(monster == null){
            return "\n" + "You are " + description + "\n" + getExitString() + "\n" + getItemOverview() + "\n";
        }
        else{
            System.out.println();
            System.out.println("Dear lord ! There is a monster in this room !");
            return "\n" + "You are " + description + "\n" + getExitString() + "\n" + getItemOverview() + "\n";
        }
    }

    /**
     * Return a string describing the room's exits, for example
     * "Exits: north west".
     * @return Details of the room's exits.
     */
    private String getExitString()
    {
        //list all the normal exits
        String unlockedExits = "Exits:";
        Set<String> keys = exits.keySet();
        for(String exit : keys) {
            unlockedExits += " " + exit;
        }
        
        //if there are no normal exits, add 'none' instead of a white line.
        if(unlockedExits.equals("Exits:"))
        {
            unlockedExits += " " + " none";
        }
        
        //list all the locked exits
        String lockedExitsString = "\nLocked exits:";
        Set<String> keys2 = lockedExits.keySet();
        for(String lockedExit : keys2)
        {
            lockedExitsString += " " + lockedExit;
        }
        
        //if there are no locked exits, add 'none' as well
        if(lockedExitsString.equals("\nLocked exits:"))
        {
            lockedExitsString += " " + "none";
        }
        
        return unlockedExits + lockedExitsString;
    }

    /**
     * Return the room that is reached if we go from this room in direction
     * "direction". If there is no room in that direction, return null.
     * @param direction The exit's direction.
     * @return The room in the given direction.
     */
    public Room getExit(String direction) 
    {
        return exits.get(direction);
    }
    
    /**
     * Check if the room in this direction is locked, and returns the name of the item
     * needed to unlock it.
     * returns "doesNotExist" if the room does not exist and null if the room isn't locked
     * @param direction The direction of the door you want to check.
     */
    public String isDoorLocked(String direction)
    {
        //if this room doesn't even exist
        if(getExit(direction) == null)
        {
            return "doesNotExist";
        }
        
        //return the name of the item needed to unlock this door.
        return lockedExits.get(direction);
    }
    
    /**
     * Unlock a locked room
     * @param direction The direction you want to unlock
     * @param item The item you want to unlock the door with
     * @return true if the door is unlocked, else false.
     */
    public boolean unlock(String direction, String item)
    {
        //get the item needed to unlock the door
        String unlockItem = lockedExits.get(direction);
        
        //if the door can't be unlocked this way, or is unlocked in the first place
        if(unlockItem == null || !unlockItem.equals(item))
        {
            return false;
        }
        //else unlock it.
        else
        {
            lockedExits.remove(direction);
            return true;
        }
    }
    
    /**
     * If the monster is defeated, this function will clear his position
     */
    public void monsterDefeated()
    {
        this.monster = null;
    }
    
    /**
     * Set this room's monster
     * @param monster The monster to add
     */
    public void setMonster(Monster monster)
    {
        this.monster = monster;
    }
    
    /**
     * Get the current monster inhabbiting this room, or null if there is none.
     */
    public Monster getMonster()
    {
        return monster;
    }
}